import {
  createContext,
  useContext,
  useState,
  useEffect,
  useCallback,
} from "react";
import * as Auth from "../api/authApi";
import { userProfileRef } from "../layout/UserProfile";
//! Next 无法获取localStorage 和window 等全局对象
// const jsonAuth = Auth.getLocalUser_Info();
// const localAuth = jsonAuth ? JSON.parse(jsonAuth) : undefined;

interface IContext {
  auth: Auth.AuthInfo;
  login: typeof Auth.login;
  register: typeof Auth.register;
  signOut: () => void;
  verifyAuth: <T extends (...args: any) => any>(callback: T) => () => T;
}

const Context = createContext({} as IContext);

type TRequest = <
  T extends (arg: Parameters<T>[number]) => Promise<Auth.UpdateAuthBack | void>
>(
  callback: T
) => (params: Parameters<T>[number]) => Promise<Auth.UpdateAuthBack | void>;

const AuthProvide = (props: any): JSX.Element => {
  const [auth, setAuth] = useState({} as any);
  useEffect(() => {
    Auth.setLocalUser_Info(auth);
  }, [auth]);

  const initAuth = useCallback(async () => {
    //用本地jwt去服务端验证 若成功则和localStorage的比较 不同则替换 失败则执行退出操作
    const result = await Auth.getAuthByToken();
    if (!result) return;
    const { status, user, message } = result;
    if (status) return setAuth(user);
    signOut();
  }, []);

  useEffect(() => {
    initAuth();
  }, [initAuth]);

  const handleRequestSetAuth: TRequest = callback => async params => {
    const result = await callback(params);
    if (!result) return;
    setAuth(result.newUser);
    return result;
  };

  const login = (auth: Auth.AuthProps) =>
    handleRequestSetAuth(Auth.login)(auth);
  const register = (auth: Auth.AuthProps) =>
    handleRequestSetAuth(Auth.register)(auth);

  const signOut = () => {
    Auth.clearLocalJWT();
    Auth.clearLocalUser_Info();
    setAuth({});
  };
  /**
   * 验证是否有用户登陆 没有则打开登陆页面
   */
  const verifyAuth: IContext["verifyAuth"] = callback => {
    if (!auth._id) {
      return userProfileRef.current!.open as any;
    }
    return callback;
  };

  return (
    <Context.Provider
      {...props}
      value={{ auth, signOut, login, register, verifyAuth }}
    />
  );
};

export const useAuth = () => useContext(Context);

export default AuthProvide;
